当前位置: 首页 > article >正文

深度学习中的张量 - 使用PyTorch进行广播和元素级操作

深度学习中的张量 - 使用PyTorch进行广播和元素级操作

元素级是什么意思?

元素级操作在神经网络编程中与张量的使用非常常见。让我们从一个元素级操作的定义开始这次讨论。

一个_元素级_操作是在两个张量之间进行的操作,它作用于各自张量中的相应元素。

一个_元素级_操作在张量之间的相应元素上进行操作。

如果两个元素被认为在张量中占据相同的位置,那么这两个元素就被称为相应的元素。位置由用来定位每个元素的索引决定。

假设我们有以下两个张量:

> t1 = torch.tensor([
    [1,2],
    [3,4]
], dtype=torch.float32)

> t2 = torch.tensor([
    [9,8],
    [7,6]
], dtype=torch.float32)

这两个张量都是秩为2的张量,形状为2 x 2​。

这意味着我们有两个长度为二的轴。第一个轴的元素是数组,第二个轴的元素是数字。

> print(t1[0])
tensor([1., 2.])

> print(t1[0][0])
tensor(1.)

这是我们现在在这个系列中用来看到的东西。好了,让我们在此基础上进一步讨论。

我们知道,如果两个元素占据张量中的相同位置,那么它们就被认为是相应的元素,位置由用来定位每个元素的索引决定。让我们看看相应元素的例子。

> t1[0][0]
tensor(1.)

> t2[0][0]
tensor(9.)

这使我们能够看到,t1​中1​的相应元素是t2​中的9​。

通过索引定义的对应关系很重要,因为它揭示了元素级操作的一个重要特征。我们可以推断出,为了执行元素级操作,张量必须具有相同数量的元素。

我们将进一步限制这个陈述。为了在它们上执行元素级操作,两个张量必须具有相同的形状。

加法是一个元素级操作

让我们看看我们的第一个元素级操作,加法。别担心,它会变得更有趣。

> t1 + t2
tensor([[10., 10.],
        [10., 10.]])

这使我们能够看到,张量之间的加法是一个元素级操作。相应位置的每对元素都被加在一起,产生一个形状相同的新张量。

所以,加法是一个元素级操作,实际上,所有的算术操作,加、减、乘和除都是元素级操作。

算术操作是元素级操作

我们经常看到的张量操作是使用标量值的算术操作。我们可以用两种方式进行这种操作:

(1) 使用这些符号操作:

> print(t + 2)
tensor([[3., 4.],
        [5., 6.]])

> print(t - 2)
tensor([[-1.,  0.],
        [ 1.,  2.]])

> print(t * 2)
tensor([[2., 4.],
        [6., 8.]])

> print(t / 2)
tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])

或者等效地,(2) 使用这些内置于张量对象的方法:

> print(t1.add(2))
tensor([[3., 4.],
        [5., 6.]])

> print(t1.sub(2))
tensor([[-1.,  0.],
        [ 1.,  2.]])

> print(t1.mul(2))
tensor([[2., 4.],
        [6., 8.]])

> print(t1.div(2))
tensor([[0.5000, 1.0000],
        [1.5000, 2.0000]])

这两种选项都有效。我们可以看到,在这两种情况下,标量值2​都应用于每个元素和相应的算术操作。

这里似乎有些问题。这些例子打破了我们之前所说的元素级操作必须在形状相同的张量上进行的规则。

标量是秩为0的张量,这意味着它们没有形状,而我们的张量t1​是一个形状为2 x 2​的秩为2的张量。

那么这如何适应呢?让我们分解一下。

首先想到的解决方案可能是,操作只是使用单个标量值,并对张量中的每个元素进行操作。

这种逻辑是可行的。然而,这有点误导,当我们在更一般的情况下使用标量时,它就崩溃了。

要不同地考虑这些操作,我们需要引入_张量广播_或广播的概念。

广播张量

广播描述了在元素级操作期间如何处理形状不同的张量。

广播是一个概念,其实现允许我们将标量添加到更高维的张量。

让我们考虑t1 + 2​操作。在这里,标量值张量被广播到t1​的形状,然后执行元素级操作。

我们可以使用broadcast_to()​ NumPy函数查看广播后的标量值是什么样子:

> np.broadcast_to(2, t1.shape)
array([[2, 2],
        [2, 2]], dtype=float32)

这意味着标量值被转换为一个像t1​一样的秩为2的张量,就像那样,形状匹配,具有相同形状的元素级规则再次发挥作用。这当然是在幕后进行的。

这段代码在这里描绘了画面。这个

> t1 + 2
tensor([[3., 4.],
        [5., 6.]])

实际上是这样的:

> t1 + torch.tensor(
    np.broadcast_to(2, t1.shape)
    ,dtype=torch.float32
)
tensor([[3., 4.],
        [5., 6.]])

此时,你可能会认为这似乎很复杂,所以让我们看一个更巧妙的例子来强调这一点。假设我们有以下两个张量。

广播的更巧妙的例子

让我们看一个更巧妙的例子来强调这一点。假设我们有以下张量。

t1 = torch.tensor([
    [1,1],
    [1,1]
], dtype=torch.float32)

t2 = torch.tensor([2,4], dtype=torch.float32)

这个元素级加法操作的结果会是什么?考虑到元素级操作的相同形状规则,这甚至可能吗?

> t1.shape
torch.Size([2, 2])

> t2.shape
torch.Size([2])

尽管这两个张量的形状不同,元素级操作是可能的,广播是使操作成为可能的关键。秩为低的张量t2​将通过广播转换以匹配秩为高的张量t1​的形状,然后像往常一样执行元素级操作。

理解广播的概念是理解这个操作如何进行的关键。和以前一样,我们可以使用NumPy的broadcast_to()​函数检查广播转换。

> np.broadcast_to(t2.numpy(), t1.shape)
array([[2., 4.],
        [2., 4.]], dtype=float32)

> t1 + t2
tensor([[3., 5.],
        [3., 5.]])

广播后,这两个张量之间的加法操作是一个形状相同的张量之间的常规元素级操作。

​​在这里插入图片描述

广播是一个比基本元素级操作更高级的话题,所以如果需要更长时间来适应这个概念,不要担心。

我们何时实际使用广播?当我们预处理数据时,尤其是进行归一化程序时,我们经常需要使用广播。

在Keras课程的TensorFlow.js部分中,有一篇文章更详细地介绍了广播。那里有一个实际的例子,并且也涵盖了确定如何广播特定张量的算法,所以请查看那篇文章,以获得关于广播的更深入讨论。

不用担心不了解TensorFlow.js。这不是一个要求,我强烈推荐那里关于广播的内容。

比较操作是元素级的

比较操作也是元素级操作。

对于两个张量之间的给定比较操作,将返回一个形状相同的新张量,每个元素包含一个torch.bool​值的True​或False​。

PyTorch 1.2.0版本中的行为变化

比较操作返回的数据类型已从torch.uint8​变更为torch.bool​(在版本21113中)。

版本1.1:

> torch.tensor([1, 2, 3]) < torch.tensor([3, 1, 2])
tensor([1, 0, 0], dtype=torch.uint8)

版本1.2:

> torch.tensor([1, 2, 3]) < torch.tensor([3, 1, 2])
tensor([True, False, False])

以下示例展示了PyTorch版本1.2.0及更高版本中的输出。

元素级比较操作示例

假设我们有以下张量:

> t = torch.tensor([
    [0,5,0],
    [6,0,7],
    [0,8,0]
], dtype=torch.float32)

让我们看看这些比较操作。

> t.eq(0)
tensor([[True, False, True],
        [False, True, False],
        [True, False, True]])

> t.ge(0)
tensor([[True, True, True],
        [True, True, True],
        [True, True, True]])

> t.gt(0)
tensor([[False, True, False],
        [True, False, True],
        [False, True, False]])

> t.lt(0)
tensor([[False, False, False],
        [False, False, False],
        [False, False, False]])

> t.le(7)
tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

从广播的角度考虑这些操作,我们可以看到最后一个操作t.le(7)​实际上是这样的:

> t <= torch.tensor(
    np.broadcast_to(7, t.shape)
    ,dtype=torch.float32
)
tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

相应地,这也可以表示为:

> t <= torch.tensor([
    [7,7,7],
    [7,7,7],
    [7,7,7]
], dtype=torch.float32)
tensor([[True, True, True],
        [True, True, True],
        [True, False, True]])

使用函数进行元素级操作

对于元素级操作,这些操作是函数形式的,可以假设函数被应用于张量的每个元素。

以下是一些示例:

> t.abs()
tensor([[0., 5., 0.],
        [6., 0., 7.],
        [0., 8., 0.]])

> t.sqrt()
tensor([[0.0000, 2.2361, 0.0000],
        [2.4495, 0.0000, 2.6458],
        [0.0000, 2.8284, 0.0000]])

> t.neg()
tensor([[-0., -5., -0.],
        [-6., -0., -7.],
        [-0., -8., -0.]])

> t.neg().abs()
tensor([[0., 5., 0.],
        [6., 0., 7.],
        [0., 8., 0.]])
一些术语

还有其他一些方式来指代元素级操作,所以我只想提一下,所有这些术语都意味着相同的事情:

  • 元素级
  • 组件级
  • 点级

如果在其他地方遇到这些术语,请记住这一点。

总结

现在,我们应该对元素级操作有了很好的理解,以及它们如何应用于神经网络和深度学习的张量操作。在下一篇文章中,我们将涵盖张量操作的最后两个类别:

  • 重塑操作
  • 元素级操作
  • 归约操作
  • 访问操作

http://www.kler.cn/a/510288.html

相关文章:

  • 安路FPGA开发工具TD:问题解决办法 及 Tips 总结
  • JetPack——databing
  • iOS - Objective-C 底层实现中的哈希表
  • 数据结构题目 课时6
  • Navicat 17 功能简介 | 商业智能 BI
  • C++速览之智能指针
  • 后盾人JS -- 好用的 JavaScript Symbol 类型
  • 【ArcGIS微课1000例】0140:总览(鹰眼)、放大镜、查看器的用法
  • C++实现设计模式---组合模式 (Composite)
  • RabbitMQ---TTL与死信
  • 参数校验 Spring Validation框架
  • 探秘Shortest与Stagehand:开启高效测试与自动化新篇
  • 【Idea】编译Spring源码 read timeout 问题
  • FastGPT结合New-api,遍享各类大模型
  • pytest全局配置文件pytest.ini
  • rabbitmq安装延迟队列
  • MinerU:高效智能PDF文档解析工具完全指南
  • pg_sql关于时间的函数
  • 刷题小白——排序
  • Vue + Nuxt 全面解析:构建高效 SSR 与 SSG 应用的最佳实践
  • CORS:跨域访问、如何在Nginx中配置允许跨域访问
  • Flink(十):DataStream API (七) 状态
  • SVG To Font 创建自己的字体图标库
  • 分布式锁详解
  • 从零开始学数据库 day2 DML
  • G1原理—7.G1的GC日志分析解读